package cn.iocoder.yudao.module.trade.service.order;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.extra.template.Template;
import cn.hutool.extra.template.TemplateConfig;
import cn.hutool.extra.template.TemplateEngine;
import cn.hutool.extra.template.TemplateUtil;
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderPrintLabelVo;
import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderPrintReceiptItemVo;
import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderPrintReceiptVo;
import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderPrintRequestVo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
@Slf4j
public class TradeOrderPrintServiceImpl implements TradeOrderPrintService {


    @Value("${print-config.fei-e.user}")
    private String USER;

    @Value("${print-config.fei-e.ukey}")
    private String UKEY;

    @Value("${print-config.fei-e.url}")
    private String URL;

    //@Value("${print_config.fei_e.label_msg_template}")
    private String LABEL_MSG_TEMPLATE = "<DIRECTION>1</DIRECTION><TEXT x='9' y='10' font='12' w='1' h='1' r='0'>#${code}  ${type}  第${index}杯</TEXT><TEXT x='9' y='50' font='12' w='1' h='2' r='0'>${name}</TEXT><TEXT x='9' y='109' font='12' w='1' h='1' r='0'>${sku}</TEXT><TEXT x='9' y='155' font='12' w='1' h='1' r='0'>${createTime}</TEXT><TEXT x='9' y='190' font='12' w='1' h='1' r='0'>${footer}</TEXT>";

    @Value("${print-config.fei-e.label-msg-template.times}")
    private String LABEL_MSG_TEMPLATE_TIMES;

    @Value("${print-config.fei-e.label-msg-template.footer}")
    private String LABEL_MSG_TEMPLATE_FOOTER;

    @Value("${print-config.fei-e.receipt-msg-template.title}")
    private String RECEIPT_MSG_TEMPLATE_TITLE;

    @Value("${print-config.fei-e.receipt-msg-template.title2}")
    private String RECEIPT_MSG_TEMPLATE_TITLE2;

    @Value("${print-config.fei-e.receipt-msg-template.qr-url}")
    private String RECEIPT_MSG_TEMPLATE_QR_URL;

    private String RECEIPT_MSG_TEMPLATE_Header =
            "<CB>${receipt.title}</CB><BR><C><BOLD>${receipt.title2}\n" +
                    "</BOLD></C><BR>店铺名称：${receipt.storeName}<BR>\n" +
                    "订单编号：${receipt.orderNO}<BR>\n" +
                    "下单时间：${receipt.createTime}<BR>\n" +
                    "取餐类型：${receipt.type}<BR>\n" +
                    "取餐号码：${receipt.pickUpNO}<BR><BR>\n" +
                    "<BOLD>名称                     单价   数量   金额   </BOLD><BR>\n" +
                    "------------------------------------------------<BR>\n";
    private String RECEIPT_MSG_TEMPLATE_footer =
            "------------------------------------------------<BR>\n"+
                    "订单金额：${receipt.totalAmount} 元<BR>\n"+
                    "优惠金额：${receipt.discountAmount} 元<BR>\n"+
                    "实付金额：${receipt.payAmount} 元<BR>\n"+
                    "<QR>${receipt.url}</QR>\n";

    @Value("${print-config.fei-e.receipt-msg-template.times}")
    private String RECEIPT_MSG_TEMPLATE_TIMES;

    @Override

    public void printLabel(String sn, List<TradeOrderPrintLabelVo> tradeOrderPrintLabelVoList) {
        Assert.notNull(sn);
        tradeOrderPrintLabelVoList.forEach(
                tradeOrderPrintLabelVo -> {
                    printLabelBySnAndVo(sn, tradeOrderPrintLabelVo);
                }
        );
    }

    @Override
    public void printLabel(String sn, TradeOrderPrintLabelVo tradeOrderPrintLabelVo) {
        printLabelBySnAndVo(sn, tradeOrderPrintLabelVo);
    }

    /**
     * 小票打印
     *
     * @param sn                  设备号
     * @param printReceiptVo      打印小票对象
     * @param printReceiptItemVoList 打印小票详情菜单对象
     */
    @Override
    public void printReceipt(String sn, TradeOrderPrintReceiptVo printReceiptVo, List<TradeOrderPrintReceiptItemVo> printReceiptItemVoList) {
        Assert.notNull(sn);
        printReceiptVo.setTitle(RECEIPT_MSG_TEMPLATE_TITLE);
        printReceiptVo.setTitle2(RECEIPT_MSG_TEMPLATE_TITLE2);
        printReceiptVo.setUrl(RECEIPT_MSG_TEMPLATE_QR_URL);
        Map<String,Object> map = new HashMap<String,Object>();
        map.put("receipt",printReceiptVo);
        //拼接上半部分内容
        String header_str = convertTemplateToString(RECEIPT_MSG_TEMPLATE_Header, map);

        String middle_str = getMiddleStr(printReceiptItemVoList,24, 8, 5, 8);

        //拼接底部内容
        String footer_str = convertTemplateToString(RECEIPT_MSG_TEMPLATE_footer,map);
        System.out.println("footer_str：\n"+footer_str);

        String content = header_str.replaceAll("\n","") + middle_str + footer_str.replaceAll("\n","");

        //构造请求参数对象
        String apiName = "Open_printMsg";//固定值
        String type = "小票打印";
        String times = RECEIPT_MSG_TEMPLATE_TIMES;
        String id = printReceiptVo.getId();
        requestAndPrint(buildTradeOrderPrintRequestVo(type,sn,apiName,times,id,content));
    }

    private void printLabelBySnAndVo(String sn, TradeOrderPrintLabelVo tradeOrderPrintLabelVo) {
        log.info("printLabel in,sn:{};tradeOrderPrintLabelVo:{}", sn, JsonUtils.toJsonString(tradeOrderPrintLabelVo));
        Assert.notBlank(sn);
        Assert.notNull(tradeOrderPrintLabelVo);
        log.info("tradeOrderPrintLabelVo index:{}", tradeOrderPrintLabelVo.getIndex());
        Map<String, Object> map = BeanUtil.beanToMap(tradeOrderPrintLabelVo);
        map.put("footer", LABEL_MSG_TEMPLATE_FOOTER);
        log.info("map index:{}", map.get("index"));
        String content = convertTemplateToString(LABEL_MSG_TEMPLATE, map);
        log.info("printLabel str:{}", content);
        //构造请求参数对象
        String apiName = "Open_printLabelMsg";//固定值
        String type = "标签打印";
        String times = LABEL_MSG_TEMPLATE_TIMES;
        String id = tradeOrderPrintLabelVo.getId();
        requestAndPrint(buildTradeOrderPrintRequestVo(type,sn,apiName,times,id,content));
    }

    private TradeOrderPrintRequestVo buildTradeOrderPrintRequestVo(String type,String sn,String apiName,String times,String id,String content){
        TradeOrderPrintRequestVo printRequestVo = new TradeOrderPrintRequestVo();
        String stime = String.valueOf(System.currentTimeMillis() / 1000);
        String sig = signature(USER, UKEY, stime);
        printRequestVo.setUrl(URL).setUser(USER).setStime(stime).setSig(sig).setApiname(apiName).setSn(sn).setContent(content).setTimes(times).setType(type).setId(id);
        return printRequestVo;
    }

    private String requestAndPrint(TradeOrderPrintRequestVo printRequestVo) {
        //通过POST请求，发送打印信息到服务器
        RequestConfig requestConfig = RequestConfig.custom()
                .setSocketTimeout(30000)//读取超时
                .setConnectTimeout(30000)//连接超时
                .build();

        CloseableHttpClient httpClient = HttpClients.custom()
                .setDefaultRequestConfig(requestConfig)
                .build();
        HttpPost post = new HttpPost(printRequestVo.getUrl());
        List<NameValuePair> nvps = new ArrayList<NameValuePair>();
        nvps.add(new BasicNameValuePair("user", printRequestVo.getUser()));
        nvps.add(new BasicNameValuePair("stime", printRequestVo.getStime()));
        nvps.add(new BasicNameValuePair("sig", printRequestVo.getSig()));
        nvps.add(new BasicNameValuePair("apiname", printRequestVo.getApiname()));//固定值,不需要修改
        nvps.add(new BasicNameValuePair("sn", printRequestVo.getSn()));
        nvps.add(new BasicNameValuePair("content", printRequestVo.getContent()));
        nvps.add(new BasicNameValuePair("times", printRequestVo.getTimes()));//打印联数
        log.info("printLabel request url:{};params:{}", printRequestVo.getUrl(), JsonUtils.toJsonString(printRequestVo));
        CloseableHttpResponse response = null;
        String result = null;;
        try {
            post.setEntity(new UrlEncodedFormEntity(nvps, "utf-8"));
            response = httpClient.execute(post);
            log.info("print:{}, response :{}", printRequestVo.getType(),JsonUtils.toJsonString(response));
            int statecode = response.getStatusLine().getStatusCode();
            if (statecode == 200) {
                HttpEntity httpentity = response.getEntity();
                if (httpentity != null) {
                    //服务器返回的JSON字符串，建议要当做日志记录起来
                    result = EntityUtils.toString(httpentity);
                    log.info("print:{}, result :{}", printRequestVo.getType(),result);
                }
            } else {
                log.error("print:{}, response statecode faile:{}",printRequestVo.getType(), statecode);
            }
        } catch (Exception e) {
            log.error("print:{}, request faile :{}",printRequestVo.getType(), e);
            e.printStackTrace();
        } finally {
            try {
                if (response != null) {
                    response.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                post.abort();
            } catch (Exception e) {
                e.printStackTrace();
            }
            try {
                httpClient.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return result;

    }

//    private  String print(String sn,String content) {
//        Assert.notNull(sn);
//        Assert.notNull(content);
//
//        RequestConfig requestConfig = RequestConfig.custom()
//                .setSocketTimeout(30000)// 读取超时
//                .setConnectTimeout(30000)// 连接超时
//                .build();
//
//        CloseableHttpClient httpClient = HttpClients.custom().setDefaultRequestConfig(requestConfig).build();
//        HttpPost post = new HttpPost(URL);
//        List<NameValuePair> nvps = new ArrayList<NameValuePair>();
//        nvps.add(new BasicNameValuePair("user", USER));
//        String STIME = String.valueOf(System.currentTimeMillis() / 1000);
//        nvps.add(new BasicNameValuePair("stime", STIME));
//        nvps.add(new BasicNameValuePair("sig", signature(USER, UKEY, STIME)));
//        nvps.add(new BasicNameValuePair("apiname", "Open_printMsg"));// 固定值,不需要修改
//        nvps.add(new BasicNameValuePair("sn", sn));
//        nvps.add(new BasicNameValuePair("content", content));
//        nvps.add(new BasicNameValuePair("times", RECEIPT_MSG_TEMPLATE_TIMES));// 打印联数
//
//        CloseableHttpResponse response = null;
//        String result = null;
//        try {
//            post.setEntity(new UrlEncodedFormEntity(nvps, "utf-8"));
//            response = httpClient.execute(post);
//            int statecode = response.getStatusLine().getStatusCode();
//            if (statecode == 200) {
//                HttpEntity httpentity = response.getEntity();
//                if (httpentity != null) {
//                    // 服务器返回的JSON字符串，建议要当做日志记录起来
//                    result = EntityUtils.toString(httpentity);
//
//                }
//            }
//        } catch (Exception e) {
//            e.printStackTrace();
//        } finally {
//            close(response, post, httpClient);
//        }
//        return result;
//    }
//
//    private void close(CloseableHttpResponse response, HttpPost post, CloseableHttpClient httpClient) {
//        try {
//            if (response != null) {
//                response.close();
//            }
//        } catch (IOException e) {
//            e.printStackTrace();
//        }
//        try {
//            post.abort();
//        } catch (Exception e) {
//            e.printStackTrace();
//        }
//        try {
//            httpClient.close();
//        } catch (IOException e) {
//            e.printStackTrace();
//        }
//    }

    //生成签名字符串
    private String signature(String USER, String UKEY, String STIME) {
        String s = DigestUtils.sha1Hex(USER + UKEY + STIME);
        return s;
    }

    private String convertTemplateToString(String templateStr, Map<String, Object> map) {
        TemplateEngine engine = TemplateUtil.createEngine(new TemplateConfig());
        Template template = engine.getTemplate(templateStr);
        String result = template.render(map);
        return result;
    }

    private String getMiddleStr(List<TradeOrderPrintReceiptItemVo> OrderPrintReceiptItemList, int b1, int b2, int b3, int b4) {

        StringBuilder stringBuilder = new StringBuilder("");

        double totals = 0.0;

        for (int i = 0; i < OrderPrintReceiptItemList.size(); i++) {
            TradeOrderPrintReceiptItemVo tradeOrderPrintReceiptItem = OrderPrintReceiptItemList.get(i);
            String title = tradeOrderPrintReceiptItem.getName();
            String price = tradeOrderPrintReceiptItem.getPrice();
            String num = tradeOrderPrintReceiptItem.getNum();
            String total = tradeOrderPrintReceiptItem.getTotal();

            price = addSpace(price, b2);
            num = addSpace(num, b3);
            total = addSpace(total, b4);
            StringBuilder otherStr =  new StringBuilder(" ").append(price).append(num).append(" ").append(total);

            int tl = 0;
            try {
                tl = title.getBytes("GBK").length;
                //System.out.println("字符串"+title+"，长度tl："+tl+",b1:"+b1);
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
            int spaceNum = (tl / b1 + 1) * b1 - tl;
            //System.out.println("sapceNUm："+spaceNum);
            if (tl < b1) {
                for (int k = 0; k < spaceNum; k++) {
                    title += " ";
                }
                title += otherStr;
            } else if (tl == b1) {
                title += otherStr;
            } else {
                List<String> list = null;
                if (isEn(title)) {
                    list = getStrList(title, b1);
                } else {
                    list = getStrList(title, b1 / 2);
                }
                String s0 = titleAddSpace(list.get(0));
                title = s0 + otherStr + "<BR>";// 添加 单价 数量 总额
                String s = "";
                for (int k = 1; k < list.size(); k++) {
                    s += list.get(k);
                }
                try {
                    s = getStringByEnter(b1, s);
                } catch (Exception e) {
                    e.printStackTrace();
                }
                title += s;
            }
            String endStr = "<BR>\n";
            if(i==OrderPrintReceiptItemList.size()-1){
                endStr = "<BR>";
            }
            stringBuilder.append(title).append(endStr);

        }

        return stringBuilder.toString();
    }

    private  String titleAddSpace(String str) {
        int k=0;
        int b = 24;
        try {
            k = str.getBytes("GBK").length;
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        for (int i = 0; i < b-k; i++) {
            str += " ";
        }
        return str;
    }

    private  String getStringByEnter(int length, String string) throws Exception {
        for (int i = 1; i <= string.length(); i++) {
            if (string.substring(0, i).getBytes("GBK").length > length) {
                return string.substring(0, i - 1) + "<BR>" + getStringByEnter(length, string.substring(i - 1));
            }
        }
        return string;
    }

    private String addSpace(String str, int size) {
        int len = str.length();
        if (len < size) {
            for (int i = 0; i < size - len; i++) {
                str += " ";
            }
        }
        return str;
    }

    private   Boolean isEn(String str) {
        Boolean b = false;
        try {
            b = str.getBytes("GBK").length == str.length();
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return b;
    }

    private  List<String> getStrList(String inputString, int length) {
        int size = inputString.length() / length;
        if (inputString.length() % length != 0) {
            size += 1;
        }
        return getStrList(inputString, length, size);
    }

    private  List<String> getStrList(String inputString, int length, int size) {
        List<String> list = new ArrayList<String>();
        for (int index = 0; index < size; index++) {
            String childStr = substring(inputString, index * length, (index + 1) * length);
            list.add(childStr);
        }
        return list;
    }

    private  String substring(String str, int f, int t) {
        if (f > str.length())
            return null;
        if (t > str.length()) {
            return str.substring(f, str.length());
        } else {
            return str.substring(f, t);
        }
    }


}
